/*
--------------------------------------------------------------------------------
				Ak-Lib. 
			 Project       	: Ak-Lib
			 Group         	: Ak-Lib R&D Team
			 Author        	: Ocean.Wang
			 Create Date 	: 05-01-2010
--------------------------------------------------------------------------------
Code Name 	:  A.K 	~v~
Description	:  Yet Another Cross-Platform Lib.
Cautions    	:
--------------------------------------------------------------------------------
Change History:
Version		: 0.1
Building 		: 05/01/10
10-05.01 first draft, build, debug and test.
--------------------------------------------------------------------------------
*/

#ifndef _INC_AK_LRU_
#define	_INC_AK_LRU_

#include "ak_types.h"
#include "ak_mem.h"

#ifdef __cplusplus
extern "C" {
#endif

/* 
** 	Here we Support the LRU Management.
** 	1. Lazy LRU RB-Tree
**	2. SNode & Expire Queue.
*/
typedef struct{
	_t_rbnode				lNode;		/* Lazy LRU RB-Tree Node */
	_t_snode				sNode;

	/* Expire */
	time_t					expire; 	/* expire time */
	int 					type;
	int 					reserv;
}_t_sysTi;

typedef struct{
	_t_sysMi 				mi;			/* Memory & K-Tree */
	_t_sysTi 				ti;			/* Tick & L-Tree */

	/* Key & CasId */
	void 			*		pKey;
	int 					lKey;
	unsigned long 			casId;
}_t_sysLruCi;



/* =====================================================================
**	The Hash Table's Memory Interface 
** 	The Hash & Compare Function
*/
typedef struct{
	void		 *	pAlk;		/* User's Internal Allocator */

	/* Heap */
	_t_sysMHeap  *	mHeap;
	
	/* After LRU, GC to Heap */
	int 		(*	fHeapGC )();
}_t_sysKLMem;

#define _KLMEM_INIT(vKLMem, vPAlk, vHeap, vHeapGC) \
do{\
	(vKLMem)->pAlk 		= (vPAlk); 	\
	(vKLMem)->mHeap 	= (vHeap);	\
	(vKLMem)->fHeapGC 	= (int (*)())(vHeapGC); 	\
}while(0)

#define _KLMEM_ASSIGN(vDst, vSrc) \
do{\
	(vDst)->pAlk 	= (vSrc)->pAlk; 	\
	(vDst)->mHeap 	= (vSrc)->mHeap;	\
	(vDst)->fHeapGC = (vSrc)->fHeapGC; 	\
}while(0)

	
typedef struct{
#if 0
	/* Buckets Hashing Func */
	int 			(*	keyHash)();
#endif
	/* Key Rb-Tree Compare Func */
	int 			(*	keyComp)();

	/* Data Fill */
	int 			(*	fDataGet)();
	int 			(*	fDataSet)();
	int 			(*	fFree)();
	int 			(*	fExpireQ)();
}_t_sysKLFunc;

#define _KLFUNC_INIT(vKLFunc, pfComp, pfGet, pfSet, pfFree, pfExpireQ) \
do{\
	(vKLFunc)->keyComp  = (int (*)())pfComp; 	\
	(vKLFunc)->fDataGet = (int (*)())pfGet; 	\
	(vKLFunc)->fDataSet = (int (*)())pfSet; 	\
	(vKLFunc)->fFree  	= (int (*)())pfFree;	\
	(vKLFunc)->fExpireQ = (int (*)())pfExpireQ; \
}while(0)

#define _KLFUNC_ASSIGN(vDst, vSrc) \
do{\
	(vDst)->keyComp = (vSrc)->keyComp; 	\
	(vDst)->fDataGet= (vSrc)->fDataGet; \
	(vDst)->fDataSet= (vSrc)->fDataSet; \
	(vDst)->fFree  	= (vSrc)->fFree;	\
	(vDst)->fExpireQ  = (vSrc)->fExpireQ; 	\
}while(0)


typedef struct {
	_t_sysLockRW		lock;
	time_t 				lazy;	/* Trigger the GC, May Lazy than Controller's Current Tick */
	time_t 			*	current;

	int 				index;
	int 				reserv;
	
	_t_rbroot 			kTree;	/* The RB-Tree of all Key-Value Pairs */
	_t_rbroot 			lTree;	/* The RB-Tree of all Lazy LRU node */

	/* Here to Co-Work with the _t_sysMi */
	_t_sysKLMem 	* 	klMem;
	_t_sysKLFunc 	* 	klFunc;

	/* Statistics */
	unsigned long		stat_Expire;
}_t_sysLruCt;


#define _SLRU_CT_INIT(pLruCt, hMem, hFunc, idx, tCurrent) 	\
	do{\
		SYS_LOCK_RW_INIT(&((pLruCt)->lock));\
		RB_CLEAR_ROOT(&((pLruCt)->kTree));\
		RB_CLEAR_ROOT(&((pLruCt)->lTree));\
		(pLruCt)->index		= idx;		\
		(pLruCt)->reserv 	= 0;		\
		(pLruCt)->lazy		= 0;		\
		(pLruCt)->current 	= tCurrent;	\
		(pLruCt)->klMem		= hMem;		\
		(pLruCt)->klFunc	= hFunc;	\
		(pLruCt)->stat_Expire = 0;		\
	}while(0)

static	__inline _t_sysLruCi *	_LruTreeK_Find(_t_sysLruCt * pCt, _t_sysLruCi * pCi, int (*fComp)())
{
	_t_rbnode		* tNode;

	tNode = rb_find(&(pCt->kTree), &(pCi->mi.kNode), fComp);
	if(tNode){
		return _O_PARENT(_t_sysLruCi, mi.kNode, tNode);
	}

	return NULL;
}

#define  LruTreeK_Rm(pCt, pCi) 	rb_erase(&((pCt)->kTree), &((pCi)->mi.kNode))

extern	_t_sysLruCi * 	LruTreeK_Get(_t_sysLruCt * pCt, _t_sysLruCi * pCi, int (*fComp)());

/* No Lock */
extern	_t_sysLruCi * 	LruTreeK_Add(_t_sysLruCt * pCt, _t_sysLruCi * pCi, int (*fComp)());
extern	_t_sysLruCi * 	LruTreeK_Del(_t_sysLruCt * pCt, _t_sysLruCi * pCi, int (*fComp)());

/* No Lock */
extern	void	LruTreeL_Add(_t_sysLruCt * pCt, _t_sysLruCi * pCi);
extern	int 	LruTreeL_Del(_t_sysLruCt * pCt, _t_sysLruCi * pCi);


extern	int 	SLru_Add(_t_sysLruCt * pCt, _t_sysLruCi * pCi);
/* Without Free */
extern	_t_sysLruCi * 	SLru_Del(_t_sysLruCt * pCt, _t_sysLruCi * pCi);
extern	_t_sysLruCi * 	SLru_DelEx(_t_sysLruCt * pCt, _t_sysLruCi * pCi);

/* With Free */
extern	int 	SLru_Rm(_t_sysLruCt * pCt, _t_sysLruCi * pCi);
extern	int 	SLru_RmEx(_t_sysLruCt * pCt, _t_sysLruCi * pCi);

_t_sysLruCi * 	SLru_Get(_t_sysLruCt * pCt, _t_sysLruCi * pCi, void * pData, size_t lData);

extern	_t_sysLruCi * 	SLru_Replace(_t_sysLruCt * pCt, _t_sysLruCi * pCi, _t_sysLruCi ** ppClea, void * pData, size_t lData);
extern	_t_sysLruCi * 	SLru_SetExpire(_t_sysLruCt * pCt, _t_sysLruCi * pCi, unsigned int expire, _t_cbentry * pJudge);

extern 	int 	SLru_Expire(_t_sysLruCt * pLruCt, time_t expire, long  lazyCnt);
extern 	time_t 	SLru_TickStep(time_t current);


#ifdef __cplusplus
}
#endif

#endif


